﻿/************************************************
*Author: KIM
*Create Time: 3/8/2017 2:56:50 PM
*CLR Version: 4.0.30319.42000
*Description:
*
*Update History:
*
***********************************************/

using ACC.Data.Entities.Common;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;

namespace ACC.Extensions.Utilities
{
    public class SocketServer
    {
        private Socket _serverSocket;

        //ACC作为client连接
        private Socket _clientSocket;
        //Socket监听线程
        private Thread _listenerThread;
        //连接Client后的工作线程
        private Thread _recvThread;
        //发送心跳的线程
        private Thread _heartBeatThread;

        private object _lockHeartBeatObj = new object();
        private readonly int _heartBeatInterval = 500;

        public int Port { get; set; }
        public bool IsRunning { get; set; }
        public bool IsConnected { get; set; }

        public SocketServer()
        {
            IsConnected = false;
        }

        public SocketServer(int port)
        {
            Port = port;
        }

        /// <summary>
        /// 启动客户端Socket Server
        /// </summary>
        public void Start()
        {
            try
            {
                _listenerThread = new Thread(new ThreadStart(SocketListener));
                _listenerThread.IsBackground = true;
                _listenerThread.Start();
                IsRunning = true;
                //启动发送心跳的线程
                _heartBeatThread = new Thread(new ThreadStart(HeartBeatLoop));
                _heartBeatThread.IsBackground = true;
                _heartBeatThread.Start();
            }
            catch (Exception ex)
            {
                Log4Helper.Error("Start socket server error: ", ex);
                throw ex;
            }
        }

        /// <summary>
        /// 停止客户端SocketServer
        /// </summary>
        public void Stop()
        {
            try
            {
                IsRunning = false;
                //停止心跳和监听线程
                if (_listenerThread != null && _listenerThread.ThreadState == ThreadState.Running)
                {
                    _listenerThread.Join();
                }
                if (_heartBeatThread != null && _heartBeatThread.ThreadState == ThreadState.Running)
                {
                    _heartBeatThread.Join();
                }
                _listenerThread = null;
                _heartBeatThread = null;

                if (_clientSocket != null)
                {
                    _clientSocket.Close();
                    _clientSocket.Dispose();

                }
                if (_serverSocket != null)
                {
                    _serverSocket.Close();
                    _serverSocket.Dispose();
                }
            }
            catch (Exception ex)
            {
                Log4Helper.Error("Stop socket server error: ", ex);
                throw ex;
            }
        }

        /// <summary>
        /// 发送心跳的循环操作
        /// </summary>
        private void HeartBeatLoop()
        {
            while (true)
            {
                Thread.Sleep(_heartBeatInterval);
                if (!IsRunning)
                {
                    continue;
                }
                lock (_lockHeartBeatObj)
                {
                    bool result = SendHeartBeatCmd();
                    if (result)
                    {
                        if (IsConnected != result)
                        {
                            if (OnConnected != null)
                            {
                                OnConnected();
                            }
                        }
                    }
                    else
                    {
                        if (IsConnected!=result)
                        {
                            if (OnDisconnected != null)
                            {
                                OnDisconnected();
                            }
                        }
                    }
                    IsConnected = result;
                }
            }
        }

        /// <summary>
        /// 监听线程执行的方法
        /// </summary>
        private void SocketListener()
        {
            //IPAddress addr = IPAddress.Parse("127.0.0.1");
            IPEndPoint ip = new IPEndPoint(IPAddress.Any, Port);
            try
            {
                _serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                _serverSocket.Bind(ip);
            }
            catch (SocketException ex)
            {
                throw ex;
            }
            _serverSocket.Listen(10);
            while (true)
            {
                if (!IsConnected )
                {
                    
                    _clientSocket = _serverSocket.Accept();
                    SendConnectCmd();
                    //连接成功后，开一个线程接收消息
                    _recvThread = new Thread(new ThreadStart(ReceiveRequest));
                    _recvThread.IsBackground = true;
                    _recvThread.Start();
                }
                Thread.Sleep(1000);
            }
        }

        private void ReceiveRequest()
        {
            byte[] buf = new byte[1024*8];
            int byteLength = 1;
            string msg = string.Empty;
            while (IsRunning)
            {
                Thread.Sleep(100);
                try
                {
                    if (_clientSocket.Available > 0)
                    {
                        byteLength = _clientSocket.Receive(buf, buf.Length, 0);
                        msg = Encoding.UTF8.GetString(buf, 0, byteLength);
                        if (byteLength > 0)
                        {
                            string[] cmds = msg.Split(new string[] {"\\r"}, StringSplitOptions.None);
                            if (cmds.Length > 0)
                            {
                                foreach (string cmd in cmds)
                                {
                                    if (!string.IsNullOrEmpty(cmd))
                                    {
                                        ACCServerRequest serverRequest = JsonHelper.ToObject<ACCServerRequest>(cmd);
                                        if (OnDisconnected != null &&
                                            serverRequest.ServerCmd == ACCCmd.Disconnect)
                                        {
                                            OnDisconnected();
                                        }
                                        else
                                        {
                                            if (serverRequest.ServerCmd != ACCCmd.Heartbeat &&
                                                OnReceiveRequest != null)
                                            {
                                                OnReceiveRequest(serverRequest);
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
                catch (Exception ex)
                {
                    Stop();
                }
            }
        }

        #region Send some commands

        public void SendConnectCmd()
        {
            TerminalRequest cmd = new TerminalRequest
            {
                ClientCmd = TerminalCmd.Connect,
                Parameter = "Connect"
            };
            int result = SendDataCmd(cmd);
            
            if (result > 0 && OnConnected != null)
            {
                IsConnected = true;
                if (OnConnected != null)
                {
                    OnConnected();
                }
            }
        }

        public void SendDisconnectCmd()
        {
            TerminalRequest cmd = new TerminalRequest
            {
                ClientCmd = TerminalCmd.Disconnect,
                Parameter = "Disconnect"
            };
            int result = SendDataCmd(cmd);
            if (result > 0 && OnDisconnected != null)
            {
                IsConnected = false;
                if (OnDisconnected != null)
                {
                    OnDisconnected();
                }
            }
        }

        public bool SendHeartBeatCmd()
        {
            TerminalRequest cmd = new TerminalRequest
            {
                ClientCmd = TerminalCmd.Heartbeat,
                Parameter = "Heartbeat"
            };
            return SendDataCmd(cmd) > 0;
        }

        /// <summary>
        /// 发送Socket命令给连接的客户端
        /// </summary>
        /// <param name="cmd"></param>
        /// <returns></returns>
        public int SendDataCmd(TerminalRequest cmd)
        {
            int result = -1;

            lock (this)
            {
                if (_clientSocket != null && _clientSocket.Connected)
                {
                    string json = JsonHelper.ToJson(cmd) + "\\r";
                    byte[] buf = Encoding.UTF8.GetBytes(json);
                    try
                    {
                        result = _clientSocket.Send(buf);
                    }
                    catch
                    {
                        //Stop();
                    }
                }
            }
            return result;
        }

        #endregion

        #region 事件和委托

        public delegate void ConnectedHandler();

        public delegate void DisconnectedHandler();

        public delegate void ReceivedRequestHandler(ACCServerRequest cmd);

        public event ConnectedHandler OnConnected;
        public event DisconnectedHandler OnDisconnected;
        public event ReceivedRequestHandler OnReceiveRequest;

        #endregion
    }
}